﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using System.Drawing;

namespace DirectX_CS
{
	public class Cartesian3dFunction : IManagedVertexBuffer, IManagedModelTransformable, IManagedMaterial, IColorable, IRangeModifiable, IDisposable
	{
		[PGBrowsable]
		public Range3d Range
		{
			get { return new Range3d(XMin, YMin, ZMin, XMax, YMax, ZMax); }
		}
		float mZMin = -10, mZMax = 10; //should be maximum and mimum of the function though... in the future.
		[PGBrowsable]
		public float ZMin
		{
			get { return mZMin; }
			set { mZMin = value; }
		}
		[PGBrowsable]
		public float ZMax
		{
			get { return mZMax; }
			set { mZMax = value; }
		}
		[PGBrowsable]
		public float XMax
		{
			get { return DataCreator.XMax;}
			set { DataCreator.XMax = value;}
		}
		[PGBrowsable]
		public float XMin
		{
			get { return DataCreator.XMin; }
			set { DataCreator.XMin = value; }
		}
		[PGBrowsable]
		public float YMax
		{
			get { return DataCreator.YMax; }
			set { DataCreator.YMax = value; }
		}
		[PGBrowsable]
		public float YMin
		{
			get { return DataCreator.YMin; }
			set { DataCreator.YMin = value; }
		}
		public event VBChangedDelegate VertexBufferChanged;

		protected PrimitiveManager renderer = null; //main memory manager..change name.
		protected Device mDevice = null;
		//protected SVector[] vertexData = null;

		[PGBrowsable]
		public CartesianDataCreator DataCreator = null;

		protected bool mEnableCallRenderPrimitives = true;
		[PGBrowsable]
		public bool EnableCallRenderPrimitives
		{
			get { return mEnableCallRenderPrimitives; }
			set { mEnableCallRenderPrimitives = value; }
		}
		protected bool mEnableCallRenderIndexedPrimitives = true;
		[PGBrowsable]
		public bool EnableCallRenderIndexedPrimitives
		{
			get { return mEnableCallRenderIndexedPrimitives; }
			set { mEnableCallRenderIndexedPrimitives = value; }
		}
		[PGBrowsable]
		public VertexFormats VertexFormat
		{
			get { return SVector.Format; }
		}
        protected Material mMaterial;
		[PGBrowsable]
		public Material Material
        {
            get {return mMaterial;}
			set { mMaterial = value; }
        }
		[PGBrowsable]
		public Color MainVertexColor
		{
			get { return DataCreator.MainVertexColor; }
			set { DataCreator.MainVertexColor = value; }
		}
        protected void InitializeMaterial()
        {
            mMaterial = new Material();
            mMaterial.Specular = Color.FromArgb(122, 255, 255,255);
            mMaterial.Ambient = Color.FromArgb(122, 255,255,255); ;
            mMaterial.Diffuse = Color.FromArgb(122,255,255,255); ;
        }
		public Cartesian3dFunction(Device device, PrimitiveManager rendManager)
		{
			InitializeMaterial();
			DataCreator = new CartesianDataCreator(null, (FloatFunc)sin, -10, 10, 30);
			DataCreator.CreateVertexData();
			renderer = rendManager;
			mDevice = device; //set before registering for sure...
			RegisterPrimitive();

		}
		public static float sin(float t)
		{
			return (float)Math.Sin((double)t);
		}
        public Cartesian3dFunction(Device device, PrimitiveManager rendManager, FloatFunc yOfX, float xmin, float xmax, int divx)
        {
			InitializeMaterial();
            DataCreator = new CartesianDataCreator(null, (FloatFunc) yOfX, null, xmin, xmax, divx);
            DataCreator.CreateVertexData();
            renderer = rendManager;
            mDevice = device; //set before registering for sure...
            RegisterPrimitive();

        }
        public Cartesian3dFunction(Device device, PrimitiveManager rendManager, FloatFunc xOfT, FloatFunc yOfT, FloatFunc zOfT, float tmin, float tmax, int divt)
        {
			InitializeMaterial();
            DataCreator = new CartesianDataCreator(xOfT, yOfT, zOfT, tmin, tmax, divt);
            DataCreator.CreateVertexData();
            renderer = rendManager;
            mDevice = device; //set before registering for sure...
            RegisterPrimitive();

        }
		/// <summary>
		/// BEGINNING OF IMPLEMENTATION of the interface..
		/// </summary>

		/// <summary>
		/// Careful because registering the primitiveWithVertices generator allocates memory for the primitives it generates, 
		/// and sometimes(depending on the settings) attempts to render the objects in its registered list.
		/// </summary>
        public Cartesian3dFunction(Device device, PrimitiveManager rendManager, ZFuncOfXY ZofXY, float xmin, float xmax, float ymin, float ymax, int divX, int divY)//, Cartesian3dSurface matchDataObject)
		{
            DataCreator = new CartesianDataCreator(ZofXY, xmin, xmax, ymin, ymax, divX, divY);
			InitializeMaterial();
			DataCreator.CreateVertexData();
			renderer = rendManager; 
			mDevice = device; //set before registering for sure...
            RegisterPrimitive();
		}
		public void Recreate()
		{
			//DataCreator = new CartesianDataCreator(ZofXY, xmin, xmax, ymin, ymax, divX, divY);
			DataCreator.CreateVertexData();
			if (VertexBufferChanged != null)
				VertexBufferChanged(this, DataCreator.GetVertices().Length); //as soon as its registered calls will probably start arriving.
		}
		public void UpdateTransform()
		{
			VertexBufferChanged(this, DataCreator.GetVertices().Length);
		}
        private void RegisterPrimitive()
        {
            PrimitiveManager.Register(this);
            if (VertexBufferChanged != null)
                VertexBufferChanged(this, DataCreator.GetVertices().Length); //as soon as its registered calls will probably start arriving.
        }

		~Cartesian3dFunction()
		{
			DisposeInstance();
		}

		public void DisposeInstance()
		{
			if (renderer != null)
				renderer.UnregisterPrimitive(this); //cannot hurt to unregister.
		}

		public Array GetVertices()
		{
            return (Array)DataCreator.GetVertices();
		}

		public int GetVerticesCount()
		{
            return DataCreator.GetVertices().Length;
		}
 
		/// <summary>
		/// Since each primitiveWithVertices should for diversity be in charge of its own representation
		/// in rendering, although the memory will be managed.
		/// </summary>
		public void RenderPrimitives(PrimitiveManager caller, int dataLength)
		{
			int EvalsX = DataCreator.DivisionsX + 1;
			int EvalsY = DataCreator.DivisionsY + 1;
			//BEGIN WORKING CODE
            int vertexStart = -1;
			for (int rowIdx = 0; rowIdx < EvalsY; rowIdx++)
			{
				vertexStart = rowIdx * EvalsX ;
                mDevice.DrawPrimitives(PrimitiveType.LineStrip, vertexStart, DataCreator.DivisionsX);
			}
			//OR FOR EXAMPLE: mDevice.DrawUserPrimitives(PrimitiveType.LineStrip,  VertexCount - 1, 0); 			//allows user to set stream
			//END WORKING CODE
		}

		long[] GetIndices()
		{
			return null;
		}
		private TransformMatrix modelView = new TransformMatrix();
		[PGBrowsable]
		public TransformMatrix ModelView
		{
			get { return modelView; }
			set { modelView = value; }
		}
        public void ManagerDestroyed(PrimitiveManager caller)
		{
			//signals to registered primitiveWithVertices generator that renderer is or has been destroyed
			//so we should stop sending messages or at least relaying them to the renderer
			renderer = null;
		}

	}//end of class..
}//end of namespace.
